aboutsummaryrefslogtreecommitdiff
path: root/src/routes/user/[user]/badges/+page.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/user/[user]/badges/+page.svelte')
-rw-r--r--src/routes/user/[user]/badges/+page.svelte634
1 files changed, 333 insertions, 301 deletions
diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte
index 4a5106aa..5a52b285 100644
--- a/src/routes/user/[user]/badges/+page.svelte
+++ b/src/routes/user/[user]/badges/+page.svelte
@@ -1,57 +1,61 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import AWC from './../../../../lib/User/BadgeWall/AWC.svelte';
-import { user, type User } from '$lib/Data/AniList/user';
-import type { Badge } from '../../../../graphql/$types';
-import { onDestroy, onMount } from 'svelte';
-import HeadTitle from '$lib/Home/HeadTitle.svelte';
-import { databaseTimeToDate, dateToInputTime, inputTimeToDatabaseTime } from '$lib/Utility/time';
-import proxy from '$lib/Utility/proxy';
-import locale from '$stores/locale';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import Message from '$lib/Loading/Message.svelte';
-import Dropdown from '$lib/Layout/Dropdown.svelte';
-import { activityText } from '$lib/Data/AniList/activity';
-import SettingHint from '$lib/Settings/SettingHint.svelte';
-import Popup from '$lib/Layout/Popup.svelte';
-import { page } from '$app/stores';
-import { browser } from '$app/environment';
-import BadgePreview from '$lib/User/BadgeWall/BadgePreview.svelte';
-import authorisedJson from '$lib/Data/Static/authorised.json';
-import identity from '$stores/identity';
-import '$lib/User/BadgeWall/badges.css';
-import Badges from '$lib/User/BadgeWall/Badges.svelte';
-import type { IndexedBadge } from '$lib/User/BadgeWall/badge';
-import { graphql } from '$houdini';
-import type { Preferences } from '../../../../graphql/$types';
-import localforage from 'localforage';
-import type { PageData } from './$types';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import AWC from "./../../../../lib/User/BadgeWall/AWC.svelte";
+import { user, type User } from "$lib/Data/AniList/user";
+import type { Badge } from "../../../../graphql/$types";
+import { onDestroy, onMount } from "svelte";
+import HeadTitle from "$lib/Home/HeadTitle.svelte";
+import {
+ databaseTimeToDate,
+ dateToInputTime,
+ inputTimeToDatabaseTime,
+} from "$lib/Utility/time";
+import proxy from "$lib/Utility/proxy";
+import locale from "$stores/locale";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import Message from "$lib/Loading/Message.svelte";
+import Dropdown from "$lib/Layout/Dropdown.svelte";
+import { activityText } from "$lib/Data/AniList/activity";
+import SettingHint from "$lib/Settings/SettingHint.svelte";
+import Popup from "$lib/Layout/Popup.svelte";
+import { page } from "$app/stores";
+import { browser } from "$app/environment";
+import BadgePreview from "$lib/User/BadgeWall/BadgePreview.svelte";
+import authorisedJson from "$lib/Data/Static/authorised.json";
+import identity from "$stores/identity";
+import "$lib/User/BadgeWall/badges.css";
+import Badges from "$lib/User/BadgeWall/Badges.svelte";
+import type { IndexedBadge } from "$lib/User/BadgeWall/badge";
+import { graphql } from "$houdini";
+import type { Preferences } from "../../../../graphql/$types";
+import localforage from "localforage";
+import type { PageData } from "./$types";
export let data: PageData;
$: ({ BadgeWallUser } = data);
$: preferences = $BadgeWallUser.fetching
- ? undefined
- : ($BadgeWallUser.data?.User?.preferences as Preferences | undefined);
+ ? undefined
+ : ($BadgeWallUser.data?.User?.preferences as Preferences | undefined);
$: if (browser && preferences && preferences.badge_wall_css) {
- const sanitise = (css: string) =>
- css
- .replace(/\/\*[\s\S]*?\*\//g, '')
- .replace(/<\/?[^>]+(>|$)/g, '')
- .replace(
- /(expression|javascript|vbscript|onerror|onload|onclick|onmouseover|onmouseout|onmouseup|onmousedown|onkeydown|onkeyup|onkeypress|onblur|onfocus|onsubmit|onreset|onselect|onchange|ondblclick):/gi,
- ''
- )
- .replace(/(behaviour|behavior|moz-binding|content):/gi, '')
- .replace(/\s+/g, ' ')
- .trim();
- const style = document.createElement('style');
-
- style.dataset.badgeWall = 'true';
- style.innerHTML = sanitise(preferences.badge_wall_css);
-
- document.head.appendChild(style);
+ const sanitise = (css: string) =>
+ css
+ .replace(/\/\*[\s\S]*?\*\//g, "")
+ .replace(/<\/?[^>]+(>|$)/g, "")
+ .replace(
+ /(expression|javascript|vbscript|onerror|onload|onclick|onmouseover|onmouseout|onmouseup|onmousedown|onkeydown|onkeyup|onkeypress|onblur|onfocus|onsubmit|onreset|onselect|onchange|ondblclick):/gi,
+ "",
+ )
+ .replace(/(behaviour|behavior|moz-binding|content):/gi, "")
+ .replace(/\s+/g, " ")
+ .trim();
+ const style = document.createElement("style");
+
+ style.dataset.badgeWall = "true";
+ style.innerHTML = sanitise(preferences.badge_wall_css);
+
+ document.head.appendChild(style);
}
const updateBadgeQuery = graphql(`
@@ -175,8 +179,8 @@ const shadowHideBadgeQuery = graphql(`
`);
interface ImportImage {
- link?: string;
- image: string;
+ link?: string;
+ image: string;
}
let editMode = false;
@@ -190,7 +194,7 @@ let loadError: string | null = null;
const isId = /^\d+$/.test(data.username);
let importImages: ImportImage[] | undefined = undefined;
let importLinks = false;
-let importCategory = '';
+let importCategory = "";
let importReplies = false;
let badger: Partial<User> | null;
let migrateMode = false;
@@ -198,313 +202,341 @@ let hideMode = false;
const authorised = authorisedJson.includes($identity.id);
let noticeDismissed = false;
-$: categoryFilter = new URLSearchParams($page.url.searchParams).get('category');
-$: loadQueryParameter = new URLSearchParams($page.url.searchParams).get('load');
+$: categoryFilter = new URLSearchParams($page.url.searchParams).get("category");
+$: loadQueryParameter = new URLSearchParams($page.url.searchParams).get("load");
type GroupedBadges = { [key: string]: IndexedBadge[] };
const setShadowHide = () => {
- if (!badger) {
- loadError = 'Something went wrong. Try refreshing.';
+ if (!badger) {
+ loadError = "Something went wrong. Try refreshing.";
- return;
- }
+ return;
+ }
- shadowHideBadgeQuery.mutate({
- id: badger.id as number
- });
+ shadowHideBadgeQuery.mutate({
+ id: badger.id as number,
+ });
};
onMount(async () => {
- if (browser && (await localforage.getItem('badgeWallNoticeDismissed'))) noticeDismissed = true;
+ if (browser && (await localforage.getItem("badgeWallNoticeDismissed")))
+ noticeDismissed = true;
- badger = isId
- ? {
- id: parseInt(data.username),
- name: 'User'
- }
- : await user(data.username);
+ badger = isId
+ ? {
+ id: parseInt(data.username),
+ name: "User",
+ }
+ : await user(data.username);
- if (!badger) {
- loadError = "Couldn't find this user.";
+ if (!badger) {
+ loadError = "Couldn't find this user.";
- return;
- }
+ return;
+ }
- awcPromise = fetch(proxy(`https://awc.moe/challenger/${badger.name}`));
+ awcPromise = fetch(proxy(`https://awc.moe/challenger/${badger.name}`));
});
onDestroy(() => {
- if (browser)
- Array.from(document.head.querySelectorAll('style')).forEach((style) => {
- if (style.dataset.badgeWall) style.remove();
- });
+ if (browser)
+ Array.from(document.head.querySelectorAll("style")).forEach((style) => {
+ if (style.dataset.badgeWall) style.remove();
+ });
});
const submitBadge = () => {
- const imageURL = document.querySelector('input[name="image_url"]') as HTMLInputElement;
- const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement;
- const description = document.querySelector('input[name="description"]') as HTMLInputElement;
- const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement;
- const category = document.querySelector('input[name="category"]') as HTMLInputElement;
- const hidden = document.querySelector('input[name="hidden"]') as HTMLInputElement;
- const source = document.querySelector('input[name="source"]') as HTMLInputElement;
- const designer = document.querySelector('input[name="designer"]') as HTMLInputElement;
-
- if (!imageURL.value) {
- error = 'Image URL cannot be empty.';
-
- return;
- }
-
- if (
- !imageURL.value.startsWith('http') ||
- (activityURL.value.length > 0 && !activityURL.value.startsWith('http'))
- ) {
- error = 'URLs must start with http or https.';
-
- return;
- }
-
- updateBadgeQuery
- .mutate({
- id: selectedBadge?.id,
- image: imageURL.value,
- post: activityURL.value || '#',
- description: description.value,
- category: category.value,
- time: time.value ? inputTimeToDatabaseTime(new Date(time.value)) : undefined,
- hidden: hidden.value === 'Hidden',
- source: source.value,
- designer: designer.value
- })
- .then(() => {
- error = null;
- imageURL.value = '';
- activityURL.value = '';
- description.value = '';
- category.value = '';
- hidden.value = 'Shown';
- selectedBadge = undefined;
- source.value = '';
- designer.value = '';
- });
+ const imageURL = document.querySelector(
+ 'input[name="image_url"]',
+ ) as HTMLInputElement;
+ const activityURL = document.querySelector(
+ 'input[name="activity_url"]',
+ ) as HTMLInputElement;
+ const description = document.querySelector(
+ 'input[name="description"]',
+ ) as HTMLInputElement;
+ const time = document.querySelector(
+ 'input[type="datetime-local"]',
+ ) as HTMLInputElement;
+ const category = document.querySelector(
+ 'input[name="category"]',
+ ) as HTMLInputElement;
+ const hidden = document.querySelector(
+ 'input[name="hidden"]',
+ ) as HTMLInputElement;
+ const source = document.querySelector(
+ 'input[name="source"]',
+ ) as HTMLInputElement;
+ const designer = document.querySelector(
+ 'input[name="designer"]',
+ ) as HTMLInputElement;
+
+ if (!imageURL.value) {
+ error = "Image URL cannot be empty.";
+
+ return;
+ }
+
+ if (
+ !imageURL.value.startsWith("http") ||
+ (activityURL.value.length > 0 && !activityURL.value.startsWith("http"))
+ ) {
+ error = "URLs must start with http or https.";
+
+ return;
+ }
+
+ updateBadgeQuery
+ .mutate({
+ id: selectedBadge?.id,
+ image: imageURL.value,
+ post: activityURL.value || "#",
+ description: description.value,
+ category: category.value,
+ time: time.value
+ ? inputTimeToDatabaseTime(new Date(time.value))
+ : undefined,
+ hidden: hidden.value === "Hidden",
+ source: source.value,
+ designer: designer.value,
+ })
+ .then(() => {
+ error = null;
+ imageURL.value = "";
+ activityURL.value = "";
+ description.value = "";
+ category.value = "";
+ hidden.value = "Shown";
+ selectedBadge = undefined;
+ source.value = "";
+ designer.value = "";
+ });
};
const removeAllBadges = () => {
- if (confirmPrune === 2) {
- confirmPrune = 0;
- } else if (confirmPrune === 0) {
- confirmPrune = 1;
+ if (confirmPrune === 2) {
+ confirmPrune = 0;
+ } else if (confirmPrune === 0) {
+ confirmPrune = 1;
- return;
- } else {
- confirmPrune = 2;
+ return;
+ } else {
+ confirmPrune = 2;
- return;
- }
+ return;
+ }
- selectedBadge = undefined;
+ selectedBadge = undefined;
- pruneBadgesQuery.mutate(null).then();
+ pruneBadgesQuery.mutate(null).then();
};
const removeBadge = (badge: Badge) => {
- if (!badge.id) return;
+ if (!badge.id) return;
- if (confirmDelete === badge.id * 2) {
- confirmDelete = 0;
- } else if (confirmDelete / 4 === badge.id) {
- confirmDelete = badge.id * 2;
+ if (confirmDelete === badge.id * 2) {
+ confirmDelete = 0;
+ } else if (confirmDelete / 4 === badge.id) {
+ confirmDelete = badge.id * 2;
- return;
- } else {
- confirmDelete = badge.id * 2;
+ return;
+ } else {
+ confirmDelete = badge.id * 2;
- return;
- }
+ return;
+ }
- selectedBadge = undefined;
+ selectedBadge = undefined;
- deleteBadgeQuery
- .mutate({
- id: badge.id
- })
- .then();
+ deleteBadgeQuery
+ .mutate({
+ id: badge.id,
+ })
+ .then();
};
const groupBadges = (badges: IndexedBadge[]) => {
- const groupedBadges: GroupedBadges = {};
-
- badges.forEach((badge) => {
- if (!badge.category) badge.category = 'Uncategorised';
-
- if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];
-
- groupedBadges[badge.category].push(badge);
- });
-
- Object.entries(groupedBadges).forEach(([_categoryKey, badges]) => {
- badges.forEach((badge, index) => {
- badge.index = index;
- });
- });
-
- return Object.entries(groupedBadges)
- .sort((a, b) => a[1].length - b[1].length)
- .sort((a, b) => {
- const pinnedCategories =
- preferences && preferences.pinned_badge_wall_categories
- ? preferences.pinned_badge_wall_categories
- : ([] as string[]);
- const aIndex = pinnedCategories.indexOf(a[0]);
- const bIndex = pinnedCategories.indexOf(b[0]);
-
- if (aIndex === -1 && bIndex === -1) return 0;
- if (aIndex === -1) return 1;
- if (bIndex === -1) return -1;
-
- return aIndex - bIndex;
- })
- .reduce((set: GroupedBadges, [key, value]) => {
- set[key] = value;
-
- return set;
- }, {});
+ const groupedBadges: GroupedBadges = {};
+
+ badges.forEach((badge) => {
+ if (!badge.category) badge.category = "Uncategorised";
+
+ if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];
+
+ groupedBadges[badge.category].push(badge);
+ });
+
+ Object.entries(groupedBadges).forEach(([_categoryKey, badges]) => {
+ badges.forEach((badge, index) => {
+ badge.index = index;
+ });
+ });
+
+ return Object.entries(groupedBadges)
+ .sort((a, b) => a[1].length - b[1].length)
+ .sort((a, b) => {
+ const pinnedCategories =
+ preferences && preferences.pinned_badge_wall_categories
+ ? preferences.pinned_badge_wall_categories
+ : ([] as string[]);
+ const aIndex = pinnedCategories.indexOf(a[0]);
+ const bIndex = pinnedCategories.indexOf(b[0]);
+
+ if (aIndex === -1 && bIndex === -1) return 0;
+ if (aIndex === -1) return 1;
+ if (bIndex === -1) return -1;
+
+ return aIndex - bIndex;
+ })
+ .reduce((set: GroupedBadges, [key, value]) => {
+ set[key] = value;
+
+ return set;
+ }, {});
};
const parsePost = async () => {
- if (importImages && importImages.length > 0) importImages = undefined;
-
- const link = (document.querySelector('#import_activity_url') as HTMLInputElement).value;
- const type = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$1');
- const id = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$2');
-
- if (type !== 'activity') return null;
-
- let text = await activityText(parseInt(id), importReplies);
-
- const images: ImportImage[] = [];
-
- if (importLinks) {
- Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('a')).forEach(
- (a) => {
- const anchor = a as HTMLAnchorElement;
-
- if (anchor.querySelector('img')) {
- images.push({
- link: anchor.href,
- image: (anchor.querySelector('img') as HTMLImageElement).src
- });
- }
- }
- );
-
- text = text.replace(/<a.*?>.*?<img.*?>.*?<\/a>/g, '');
-
- Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')).forEach(
- (img) => {
- const image = img as HTMLImageElement;
-
- images.push({
- image: image.src
- });
- }
- );
- } else {
- Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')).forEach(
- (img) => {
- const image = img as HTMLImageElement;
-
- images.push({
- image: image.src
- });
- }
- );
- }
-
- importImages = images;
+ if (importImages && importImages.length > 0) importImages = undefined;
+
+ const link = (
+ document.querySelector("#import_activity_url") as HTMLInputElement
+ ).value;
+ const type = link.replace(/.*\/(activity|thread)\/(\d+).*/, "$1");
+ const id = link.replace(/.*\/(activity|thread)\/(\d+).*/, "$2");
+
+ if (type !== "activity") return null;
+
+ let text = await activityText(parseInt(id), importReplies);
+
+ const images: ImportImage[] = [];
+
+ if (importLinks) {
+ Array.from(
+ new DOMParser().parseFromString(text, "text/html").querySelectorAll("a"),
+ ).forEach((a) => {
+ const anchor = a as HTMLAnchorElement;
+
+ if (anchor.querySelector("img")) {
+ images.push({
+ link: anchor.href,
+ image: (anchor.querySelector("img") as HTMLImageElement).src,
+ });
+ }
+ });
+
+ text = text.replace(/<a.*?>.*?<img.*?>.*?<\/a>/g, "");
+
+ Array.from(
+ new DOMParser()
+ .parseFromString(text, "text/html")
+ .querySelectorAll("img"),
+ ).forEach((img) => {
+ const image = img as HTMLImageElement;
+
+ images.push({
+ image: image.src,
+ });
+ });
+ } else {
+ Array.from(
+ new DOMParser()
+ .parseFromString(text, "text/html")
+ .querySelectorAll("img"),
+ ).forEach((img) => {
+ const image = img as HTMLImageElement;
+
+ images.push({
+ image: image.src,
+ });
+ });
+ }
+
+ importImages = images;
};
const importBadges = () =>
- fetch(
- `/api/badges?import=true
- ${importCategory.length > 0 ? `&category=${encodeURIComponent(importCategory)}` : ''}
+ fetch(
+ `/api/badges?import=true
+ ${importCategory.length > 0 ? `&category=${encodeURIComponent(importCategory)}` : ""}
`,
- {
- method: 'PUT',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(
- importImages?.map((image) => ({
- image: image.image,
- post: image.link || '#',
- category: importCategory
- }))
- )
- }
- ).then(() => {
- importMode = false;
- importImages = undefined;
- });
+ {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(
+ importImages?.map((image) => ({
+ image: image.image,
+ post: image.link || "#",
+ category: importCategory,
+ })),
+ ),
+ },
+ ).then(() => {
+ importMode = false;
+ importImages = undefined;
+ });
const migrateCategory = () => {
- fetch(
- `/api/badges?migrate=true&original=${encodeURIComponent(
- (document.querySelector('#migrate_original') as HTMLInputElement).value
- )}&new=${encodeURIComponent(
- (document.querySelector('#migrate_new') as HTMLInputElement).value
- )}`,
- {
- method: 'PUT'
- }
- ).then(() => (migrateMode = false));
+ fetch(
+ `/api/badges?migrate=true&original=${encodeURIComponent(
+ (document.querySelector("#migrate_original") as HTMLInputElement).value,
+ )}&new=${encodeURIComponent(
+ (document.querySelector("#migrate_new") as HTMLInputElement).value,
+ )}`,
+ {
+ method: "PUT",
+ },
+ ).then(() => (migrateMode = false));
};
const hideCategory = () => {
- hideCategoryQuery
- .mutate({
- category: (document.querySelector('#category_hide') as HTMLInputElement).value
- })
- .then(() => (hideMode = false));
+ hideCategoryQuery
+ .mutate({
+ category: (document.querySelector("#category_hide") as HTMLInputElement)
+ .value,
+ })
+ .then(() => (hideMode = false));
};
const removeHiddenBadges = (isOwner: boolean, badges: IndexedBadge[]) =>
- isOwner || authorised ? badges : badges.filter((b) => !b.hidden && !b.shadow_hidden);
+ isOwner || authorised
+ ? badges
+ : badges.filter((b) => !b.hidden && !b.shadow_hidden);
const setAdjacentCursor = (badges: IndexedBadge[], direction: number) => {
- const currentCategory = selectedBadge?.category || 'Uncategorised';
- const currentBadge = selectedBadge?.index;
- const categoryBadges = groupBadges(badges)[currentCategory];
+ const currentCategory = selectedBadge?.category || "Uncategorised";
+ const currentBadge = selectedBadge?.index;
+ const categoryBadges = groupBadges(badges)[currentCategory];
- if (!currentCategory || currentBadge === undefined) return;
+ if (!currentCategory || currentBadge === undefined) return;
- let previousBadge = categoryBadges[currentBadge + direction];
+ let previousBadge = categoryBadges[currentBadge + direction];
- while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
- previousBadge = categoryBadges[previousBadge.index + direction];
+ while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
+ previousBadge = categoryBadges[previousBadge.index + direction];
- if (previousBadge) selectedBadge = previousBadge;
+ if (previousBadge) selectedBadge = previousBadge;
};
const adjacentBadgeExists = (
- selectedBadge: IndexedBadge | undefined,
- badges: IndexedBadge[],
- direction: number
+ selectedBadge: IndexedBadge | undefined,
+ badges: IndexedBadge[],
+ direction: number,
) => {
- const currentCategory = selectedBadge?.category || 'Uncategorised';
- const currentBadge = selectedBadge?.index;
- const categoryBadges = groupBadges(badges)[currentCategory];
+ const currentCategory = selectedBadge?.category || "Uncategorised";
+ const currentBadge = selectedBadge?.index;
+ const categoryBadges = groupBadges(badges)[currentCategory];
- if (!currentCategory || currentBadge === undefined || !categoryBadges) return;
+ if (!currentCategory || currentBadge === undefined || !categoryBadges) return;
- let previousBadge = categoryBadges[currentBadge + direction];
+ let previousBadge = categoryBadges[currentBadge + direction];
- while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
- previousBadge = categoryBadges[previousBadge.index + direction];
+ while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
+ previousBadge = categoryBadges[previousBadge.index + direction];
- return previousBadge;
+ return previousBadge;
};
const castAsStringArray = (array: unknown[]) => array as string[];
@@ -512,20 +544,20 @@ const castAsStringArray = (array: unknown[]) => array as string[];
const castBadgesToIndexedBadges = (array: unknown[]) => array as IndexedBadge[];
const shadowHideBadge = () => {
- if (!selectedBadge && !authorised) return;
+ if (!selectedBadge && !authorised) return;
- if (!badger) {
- loadError = 'Something went wrong. Try refreshing.';
+ if (!badger) {
+ loadError = "Something went wrong. Try refreshing.";
- return;
- }
+ return;
+ }
- shadowHideBadgeQuery
- .mutate({
- id: badger.id as number,
- state: selectedBadge?.shadow_hidden as boolean
- })
- .then();
+ shadowHideBadgeQuery
+ .mutate({
+ id: badger.id as number,
+ state: selectedBadge?.shadow_hidden as boolean,
+ })
+ .then();
};
</script>